package com.nexus.plugin.amqp.proxy;

import com.nexus.core.utils.SpringContextHolder;
import com.nexus.plugin.amqp.annotion.RabbitSender;
import com.nexus.plugin.amqp.service.RabbitService;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.cglib.proxy.Proxy;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Set;

/**
 * 消息队列发送代理注册
 * 在Bean实例初始化完毕后执行
 *
 * @Date 2025/9/24 22:49
 * @Author luzhengning
 **/
@Component
public class RabbitSenderRegistrar implements SmartInitializingSingleton {

    /**
     * 消息发送注解包扫描
     *
     * @Date 2025/9/26 16:16
     * @Author luzhengning
     **/
    private final static String[] RabbitSenderPath = new String[]{"com.nexus"};
    private final ConfigurableApplicationContext applicationContext;
    private ResourceLoader resourceLoader;
    private Environment environment;

    public RabbitSenderRegistrar(ConfigurableApplicationContext applicationContext, ResourceLoader resourceLoader, Environment environment) {
        this.applicationContext = applicationContext;
        this.resourceLoader = resourceLoader;
        this.environment = environment;
    }

    /**
     * 消息队列发送注解代理注册
     *
     * @Date 2025/9/26 16:10
     * @Author luzhengning
     **/
    @Override
    public void afterSingletonsInstantiated() {
        //Bean工厂，用于注册代理
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        //@RabbitSender注解扫描器
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
            // 只扫描interface接口
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
            }
        };
        scanner.setEnvironment(environment);
        scanner.setResourceLoader(resourceLoader);
        scanner.addIncludeFilter(new AnnotationTypeFilter(RabbitSender.class));
        //遍历包路径获取包含RabbitSender注解类
        for (String basePackage : RabbitSenderPath) {
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                registerProxyBean(candidateComponent, beanFactory);
            }
        }
    }

    /**
     * 创建代理并注册到Bean容器中
     *
     * @Date 2025/9/26 16:15
     * @Author luzhengning
     **/
    private boolean registerProxyBean(BeanDefinition beanDefinition, ConfigurableListableBeanFactory beanFactory) {
        String className = beanDefinition.getBeanClassName();
        try {
            Class<?> clazz = Class.forName(className);
            if (!clazz.isInterface()) {
                return false;
            }
            // 为接口创建代理
            Object proxy = createProxy(clazz);
            // 获取Bean名称（首字母小写）
            String beanName = StringUtils.uncapitalize(clazz.getSimpleName());
            // 将代理对象注册为单例Bean
            beanFactory.registerSingleton(beanName, proxy);
            // 初始化接口方法注解上标注的交换机，队列等
            RabbitService rabbitService = SpringContextHolder.getBean(RabbitService.class);
            for (Method method : clazz.getMethods()) {
                RabbitSender annotation = method.getAnnotation(RabbitSender.class);
                if (annotation == null) {
                    continue;
                }
                rabbitService.createQueue(annotation);
            }
            return true;
        } catch (Exception e) {
            throw new RuntimeException("创建消息队列发送代理失败: " + className, e);
        }
    }

    /**
     * 创建消息队列发送代理
     *
     * @Date 2025/9/26 16:22
     * @Author luzhengning
     **/
    @SuppressWarnings("unchecked")
    public <T> T createProxy(Class<T> interfaceClass) {
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                new Class<?>[]{interfaceClass},
                new RabbitSenderInvocationHandler(interfaceClass)
        );
    }

}